#ifndef __LOGGER_H_
#define __LOGGER_H_

#include <time.h>
#include <limits.h>
#include "queue.h"

#define MAGIC_NUMBER 100

enum LOG_LEVEL {
	DEFAULT,
	DEBUG,
	INFO,
	NOTICE,
	WARNING,
	ERROR,
	EMERG,
};

struct logger {
	pthread_t tid;
	queue_t *queue;
	FILE *file;
	int log_level;
} logg;

void log_init(int log_level, const char *log_file);
void log_deinit();

static unsigned long long int counter = 0;

static char *get_time_str(void) {
	time_t t = time(NULL);
	return ctime(&t);
}

static int mget_time(void) {
	return time(NULL);
}

static unsigned long long int add_cnt(void) {
	if (ULLONG_MAX - counter < MAGIC_NUMBER)	{
		__sync_lock_test_and_set(&counter, 0);
		fprintf(logg.file, "%s\n", "IMPORTANT NOTICE: Log counter was reset.");
	}
	return __sync_fetch_and_add(&counter, 1) + 1;
}

#define LOG_DEBUG(...)                                                                           \
	do {                                                                                           \
		if (logg.log_level <= DEBUG) {                                                               \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n DEBUG: %s",       \
							add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);       \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)


#define LOG_INFO(...)                                                                            \
	do {                                                                                           \
		if (logg.log_level <= INFO) {                                                                \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n INFO: %s",        \
							add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);       \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)


#define LOG_NOTICE(...)                                                                          \
	do {                                                                                           \
		if (logg.log_level <= NOTICE) {                                                              \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n NOTICE: %s",      \
						add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);         \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)


#define LOG_WARNING(...)                                                                         \
	do {                                                                                           \
		if (logg.log_level <= WARNING) {                                                             \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n WARNING: %s",     \
							add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);       \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)


#define LOG_ERROR(...)                                                                           \
	do {                                                                                           \
		if (logg.log_level <= ERROR) {                                                               \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n ERROR: %s",       \
							add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);       \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)


#define LOG_EMERG(...)                                                                           \
	do {                                                                                           \
		if (logg.log_level <= EMERG) {                                                               \
			char buf[MESSAGE_MAXLEN];                                                                  \
			sprintf(buf, "Log #%lld Time: %s [file (%s), function (%s) at line:%d]\n EMERG: %s",       \
						add_cnt(), get_time_str(), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);         \
			enqueue(logg.queue,buf);                                                                   \
		}                                                                                            \
	} while(0)

#endif // __LOGGER_H_
